/*
 * token_list.c
 *
 * Group: Fantastic Five
 * Date: 4/25/08
 *
 * Description: Defines a linked list to store unparsed tokens (used by lexer)
 */

#include "token_list.h"

/* Creates and initializes a new token list */
struct token_list * new_token_list()
{
    struct token_list *new_tl = (struct token_list *)malloc(sizeof(struct token_list));
    new_tl->head = NULL;
    new_tl->tail = NULL;
    new_tl->count = 0;

    return new_tl;
}

/* Creates and initializes a new token */
struct token * new_token(int num, union value val, enum lexeme t)
{
    struct token *new_token = (struct token *)malloc(sizeof(struct token));
    new_token->next = NULL;
    new_token->prev = NULL;
    new_token->linenum = num;
    new_token->v = val;
    new_token->type = t;

    return new_token;
}

/* Pushes token t onto back of token list */
void push_token(struct token *t, struct token_list *tl)
{
    if(tl->head == NULL || tl->tail == NULL) /* check for empty list */
    { /* initialize head and tail pointers to new token */
        t->next = NULL;
        t->prev = NULL;
        tl->tail = t;
        tl->head = t;
        tl->count = 1;
    }
    else /* push token onto back of list */
    {
        t->next = NULL;
        t->prev = tl->tail;
        t->prev->next = t;
        tl->tail = t;
        tl->count++;
    }
}

/* Pops off token at beginning of token list */
struct token * pop_token(struct token_list *tl)
{
    struct token *temp = tl->head;

    if(temp == NULL || tl->count == 0) /* check for invalid list */
    {
        fprintf(stderr, "No tokens to pop off list.\n");
    }
    else if(tl->head == tl->tail) /* check for list with single item */
    { /* change all list pointers to null and adjust count */
        tl->head = NULL;
        tl->tail = NULL;
        tl->count = 0;
    }
    else /* pop first token off list, adjust head pointer and count */
    {
        tl->head = tl->head->next;
        tl->head->prev = NULL;
        tl->count--;
    }

    return temp;
}

/* Removes token rem from token list */
void remove_token(struct token *rem, struct token_list *tl)
{
    if(tl->count == 0 || tl == NULL) /* Check for empty list */
    {
        fprintf(stderr, "Cannot remove token from list.\n");
        return;
    }
    else if(tl->count == 1 || tl->head == rem) /* check if only one token in list or token is head, pop token off if so */
    {
        pop_token(tl);
    }
    else if(tl->tail == rem) /* check if token to be removed is tail, adjust tail and count if so */
    {
        tl->tail = rem->prev;
        tl->tail->next = NULL;
        tl->count--;
        free(rem);
        rem = NULL;
    }
    else /* remove token from list and adjust necessary pointers */
    {
        rem->prev->next = rem->next;
        rem->next->prev = rem->prev;
        tl->count--;
        free(rem);
        rem = NULL;
    }
}

/* Checks to see if list contains tokens, return 1 if empty, 0 if not */
int no_tokens(struct token_list *tl)
{
    if(tl->count > 0)
        return 0;
    else
        return 1;
}

/* Removes all tokens from token list */
void empty_token_list(struct token_list *tl)
{
    struct token *cur = tl->head;

    if(cur == NULL || tl->count == 0)
    {
        return;
    }
    
    while(tl->count > 0) /* pop all tokens off */
    {
        cur = pop_token(tl);
        free(cur);
    }
}
